#include <unistd.h>

#include <algorithm>
#include <chrono>
#include <deque>
#include <iostream>
#include <thread>
#include <tuple>
using namespace std;

void test() {
    deque<chrono::steady_clock::time_point> time_fifo;

    while (true) {
        auto value = rand() % 1024;

        bool flag = value % 3 == 0 ? true : false;

        if (flag) {
            auto current = chrono::steady_clock::now();

            // 超过5s的不统计
            while (!time_fifo.empty() && (current - time_fifo.front()) > chrono::seconds(5))
                time_fifo.pop_front();

            time_fifo.push_back(current);

            // 持续3s且超过10次，报警
            if ((time_fifo.back() - time_fifo.front()) > chrono::seconds(3) && time_fifo.size() > 10) {
                cout << "Block Alarm!" << time_fifo.size() << endl;
                time_fifo.clear();
            }
        }

        usleep(1000 * 100);
    }
}

template <typename T>
class TimeFifo {
public:
    explicit TimeFifo(int valid_time) : valid_time_(valid_time) {}
    ~TimeFifo() { fifo_.clear(); }

    void Push(T value) {
        auto current = chrono::steady_clock::now();

        while (!fifo_.empty()) {
            if ((current - get<1>(fifo_.front())) > valid_time_)
                fifo_.pop_front();
            else
                break;
        }

        fifo_.push_back(make_tuple(value, current));
    }

    float GetPercent(const T& value) {
        auto sum =
            count_if(fifo_.begin(), fifo_.end(), [value](const tuple<T, chrono::steady_clock::time_point>& item) {
                return get<0>(item) > value;
            });
        // cout << "sum:" << sum << " size:" << fifo_.size() << endl;
        return static_cast<float>(sum) / static_cast<float>(fifo_.size());
    }

private:
    deque<tuple<T, chrono::steady_clock::time_point>> fifo_;
    chrono::seconds                                   valid_time_;
};

void test2() {
    TimeFifo<int> fifo(10);
    while (true) {
        auto value = rand() % 1024;
        fifo.Push(value);
        if (fifo.GetPercent(500) > 0.6) cout << "Alarm!" << endl;

        usleep(1000 * 100);
    }
}

int main(int argc, char** argv) {
    // thread t(test);

    // t.join();

    cout << "Test2" << endl;
    thread t2(test2);
    t2.join();

    (void)argc;
    (void)argv;

    return 0;
}
